package com.ruoyi.washer.common;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.client.j2se.MatrixToImageConfig;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.ruoyi.common.utils.StringUtils;
import org.apache.commons.codec.binary.Base64;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.HashMap;
import java.util.Map;

@Service
public class QRCodeUtil {
    //二维码的宽高
    //二维码的宽高
    private static final int WIDTH=500;
    private static final int HEIGHT=500;
    // 加文字二维码高
    private static final int WORDHEIGHT = 500;


    /**
     *  生成二维码图片
     * @param content 二维码的内容
     * @return
     */
    public static BufferedImage createQRCode(String content) {

        Map<EncodeHintType, Object> hints= new HashMap<EncodeHintType, Object>();
        //容错级别L>M>Q>H(级别越高扫描时间越长)
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
        //字符编码
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        hints.put(EncodeHintType.MARGIN, 0);//白边的宽度，可取0~4
        BufferedImage image=null;
        try {
            MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
            //生成矩阵数据
            BitMatrix bitMatrix=multiFormatWriter.encode(content,
                    BarcodeFormat.QR_CODE,WIDTH,HEIGHT,hints);
            int w = bitMatrix.getWidth();
            int h = bitMatrix.getHeight();
            //生成二维码bufferedImage图片
            image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
            // 开始利用二维码数据创建Bitmap图片，分别设为黑（0xFFFFFFFF）白（0xFF000000）两色
            for (int x = 0; x < w; x++) {
                for (int y = 0; y < h; y++) {
                    image.setRGB(x, y, bitMatrix.get(x, y) ?
                            MatrixToImageConfig.BLACK : MatrixToImageConfig.WHITE);
                }
            }


        } catch (Exception e) {
            throw new RuntimeException("生成二维码失败："+e.getMessage());
        }
        return image;

    }
    /**
     * 二维码底部加上文字
     * @param image 传入二维码对象
     * @param words 显示的文字内容
     * @return
     */
    private static BufferedImage insertWords(BufferedImage image,String words){
        BufferedImage outImage = null;
        if (  StringUtils.isNotBlank(words)){
            outImage= new BufferedImage(WORDHEIGHT, WORDHEIGHT, BufferedImage.TYPE_4BYTE_ABGR);
            Graphics2D outg = outImage.createGraphics();

            // 画二维码到新的面板
            outg.drawImage(image, 50, 50, image.getWidth(), image.getHeight(), null);
            // 画文字到新的面板
            outg.setColor(Color.BLACK);
            outg.setFont(new Font("微软雅黑", Font.PLAIN, 25)); // 字体、字型、字号

            int strWidth = outg.getFontMetrics().stringWidth(words);

            int singleFD=outg.getFontMetrics().stringWidth("2");
            int grow=WIDTH/singleFD-1;
            //长度过长就截取超出二维码宽度部分换行
            if (strWidth > WIDTH) {
                System.out.println("oooooooooooooooooooooooooo");
                String serialnum1 = words.substring(0, grow);
                String serialnum2 = words.substring(grow, words.length());
                outg.drawString(serialnum1, 5, image.getHeight() + (outImage.getHeight() - image.getHeight()) / 2 );
                BufferedImage outImage2 = new BufferedImage(WIDTH, WORDHEIGHT, BufferedImage.TYPE_4BYTE_ABGR);
                Graphics2D outg2 = outImage2.createGraphics();
                outg2.drawImage(outImage, 0, 0, outImage.getWidth(), outImage.getHeight(), null);
                outg2.setColor(Color.BLACK);
                // 字体、字型、字号
                outg2.setFont(new Font("微软雅黑", Font.PLAIN, 30));
                //参数：显示的内容、起始位置x、起始的y
                outg2.drawString(serialnum2,5, outImage.getHeight() + (outImage2.getHeight() - outImage.getHeight()) / 2 );
                outg2.dispose();
                outImage2.flush();
                outImage = outImage2;
            } else {
                // 画文字
                outg.drawString(words, (WORDHEIGHT - strWidth) / 2,
                        image.getHeight() + (outImage.getHeight() - image.getHeight()) / 2 +35);
            }

            outg.draw3DRect(5,5,WORDHEIGHT-10,WORDHEIGHT-10,true);
            outg.dispose();
            outImage.flush();
            image.flush();
        }

        return outImage;
    }

    /**
     * 二维码底部和顶部加上文字
     * @param image 传入二维码对象
     * @param words 显示的文字内容
     * @return
     */
    private static BufferedImage insertWords(BufferedImage image,String words,String top){
        BufferedImage outImage = null;
        if (  StringUtils.isNotBlank(words)){
            outImage= new BufferedImage(WORDHEIGHT, WORDHEIGHT, BufferedImage.TYPE_4BYTE_ABGR);
            Graphics2D outg = outImage.createGraphics();
            //绘制白色背景
            outg.setColor(Color.WHITE);
            outg.fillRect(0, 0, WORDHEIGHT, WORDHEIGHT);
            // 画二维码到新的面板
            outg.drawImage(image, 35, 50, image.getWidth(), image.getHeight(), null);
            // 画文字到新的面板
            outg.setColor(Color.BLACK);
            outg.setFont(new Font("微软雅黑", Font.PLAIN, 25)); // 字体、字型、字号

            int strWidth = outg.getFontMetrics().stringWidth(words);

            int singleFD=outg.getFontMetrics().stringWidth("2");
            int grow=WIDTH/singleFD-1;
            //长度过长就截取超出二维码宽度部分换行
            if (strWidth > WIDTH) {
                System.out.println("oooooooooooooooooooooooooo");
                String serialnum1 = words.substring(0, grow);
                String serialnum2 = words.substring(grow, words.length());
                outg.drawString(serialnum1, 5, image.getHeight() + (outImage.getHeight() - image.getHeight()) / 2 );
                BufferedImage outImage2 = new BufferedImage(WIDTH, WORDHEIGHT, BufferedImage.TYPE_4BYTE_ABGR);
                Graphics2D outg2 = outImage2.createGraphics();
                outg2.drawImage(outImage, 0, 0, outImage.getWidth(), outImage.getHeight(), null);
                outg2.setColor(Color.BLACK);
                // 字体、字型、字号
                outg2.setFont(new Font("微软雅黑", Font.PLAIN, 30));
                //参数：显示的内容、起始位置x、起始的y
                outg2.drawString(serialnum2,5, outImage.getHeight() + (outImage2.getHeight() - outImage.getHeight()) / 2 );
                outg2.dispose();
                outImage2.flush();
                outImage = outImage2;
            } else {
                // 下方画文字
                /*outg.drawString(words, (WORDHEIGHT - strWidth) / 2,
                        image.getHeight() + (outImage.getHeight() - image.getHeight()) / 2 +50);*/
                //上方画文字
                int strWidthTop = outg.getFontMetrics().stringWidth(top);
                outg.drawString(top, (WORDHEIGHT - strWidthTop) / 2,
                        35);
            }

            //outg.draw3DRect(5,5,WORDHEIGHT-10,WORDHEIGHT-10,true);
            outg.dispose();
            outImage.flush();
            image.flush();
        }

        return outImage;
    }

    /**
     * 生成二维码下方不带文字
     * @return
     */
    public static String getQRCode(String content,String savePath) {
        BufferedImage image=createQRCode(content);
        try {

            //字节数组流包装输出对象流
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(image, "png", baos);//将图片写入到输出流
            ImageIO.write(image, "png", new File(savePath));//直接写入某路径
            return Base64.encodeBase64URLSafeString(baos.toByteArray());

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("写出图片流失败");
        }

    }

    public static String getQRCode(BufferedImage image2,String words,String top,String savePath) {

        BufferedImage image = insertWords(image2, words,top);
        try {

            //字节数组流包装输出对象流
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            image.flush();
            //将图片写入到输出流
            ImageIO.write(image, "png", baos);

            ImageIO.write(image, "png", new File(savePath));//直接写入某路径
            return Base64.encodeBase64URLSafeString(baos.toByteArray());

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("写出图片流失败!!!");
        }

    }

    /**
     * 生成的二维码下方和上方带文字
     * @return
     */
    public static String getQRCode(String content,String words,String top,String savePath) {

        BufferedImage image = insertWords(createQRCode(content), words,top);
        try {

            //字节数组流包装输出对象流
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            image.flush();
            //将图片写入到输出流
            ImageIO.write(image, "png", baos);

            ImageIO.write(image, "png", new File(savePath));//直接写入某路径
            return Base64.encodeBase64URLSafeString(baos.toByteArray());

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("写出图片流失败!!!");
        }

    }

    /**
     * 生成的二维码下方带文字
     * @return
     */
    public static String getQRCode(String content,String words,String savePath) {

        BufferedImage image = insertWords(createQRCode(content), words);
        try {

            //字节数组流包装输出对象流
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            image.flush();
            //将图片写入到输出流
            ImageIO.write(image, "png", baos);

            ImageIO.write(image, "png", new File(savePath));//直接写入某路径
            return Base64.encodeBase64URLSafeString(baos.toByteArray());

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("写出图片流失败!!!");
        }

    }

    public String getQRCodeAndSave(String content,String words,String savePath) {

        BufferedImage image = insertWords(createQRCode(content), words);
        try {

            //字节数组流包装输出对象流
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            image.flush();
            //将图片写入到输出流
            ImageIO.write(image, "png", baos);

            ImageIO.write(image, "png", new File(savePath));//直接写入某路径
            return Base64.encodeBase64URLSafeString(baos.toByteArray());

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("写出图片流失败!!!");
        }

    }

    public String getQRCodeNotSave(String content,String words) {

        BufferedImage image = insertWords(createQRCode(content), words);
        try {

            //字节数组流包装输出对象流
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            image.flush();
            //将图片写入到输出流
            ImageIO.write(image, "png", baos);
            return Base64.encodeBase64URLSafeString(baos.toByteArray());

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("写出图片流失败!!!");
        }

    }
    /**
     *  生成解析二维码
     * @param content 二维码的内容
     * @return
     */
    public static String parseQRCode(String filePath) {
        //二维码编码相关的参数
        Map<DecodeHintType, Object> hints= new HashMap<DecodeHintType, Object>();
        //字符编码
        hints.put(DecodeHintType.CHARACTER_SET, "UTF-8");

        BufferedImage image=null;
        try {
            File file = new File(filePath);
            image = ImageIO.read(file);

            if (image == null) {
                System.out.println("the decode image may be not exit.");
            }
            LuminanceSource source = new BufferedImageLuminanceSource(image);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
            //解析二维码
            Result result = new MultiFormatReader().decode(bitmap, hints);
            String content=result.getText();

            return content;
        } catch (Exception e) {
            throw new RuntimeException("解析二维码失败："+e.getMessage());
        }

    }

    public static void main(String args[]){
        String content="https://chargingpole.letlink.net/1CDZ022106070001/08";
        String words="11111111";
        String top="11111111";
        String savePath1="d:/test1.png";
        String savePath2="d:/test2.png";
        QRCodeUtil.getQRCode(content,"11111111","11111111",savePath1);
        QRCodeUtil.getQRCode(content,"08","11111111",savePath2);
        System.out.println("Base64str=============");

    }
}
